package com.bootx.service.impl;

import com.bootx.common.Page;
import com.bootx.common.Pageable;
import com.bootx.dao.LotteryRecordDao;
import com.bootx.entity.BetInfo;
import com.bootx.entity.BetRecord;
import com.bootx.entity.LotteryRecord;
import com.bootx.entity.LotteryRecordNum;
import com.bootx.pojo.PredictInfo;
import com.bootx.predict.util.PredictUtils;
import com.bootx.repository.LotteryRecordRepository;
import com.bootx.service.BetInfoService;
import com.bootx.service.BetRecordService;
import com.bootx.service.LotteryRecordNumService;
import com.bootx.service.LotteryRecordService;
import com.bootx.util.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import jakarta.persistence.criteria.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author black
 */
@Service
public class LotteryRecordServiceImpl extends BaseServiceImpl<LotteryRecord,Long> implements LotteryRecordService {

    @Resource
    private LotteryRecordDao lotteryRecordDao;

    @Resource
    private LotteryRecordNumService  lotteryRecordNumService;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private LotteryRecordRepository lotteryRecordRepository;
    @Resource
    private BetInfoService betInfoService;
    @Resource
    private BetRecordService betRecordService;


    public Integer getMaxOrder(LotteryRecord lotteryRecord){
      try {
          Integer i = jdbcTemplate.queryForObject("select max(orders) from lotteryrecord where lotteryCode=? and date=?", Integer.class, lotteryRecord.getLotteryCode(), lotteryRecord.getDate());
          return i==null?0:i;
      }catch (Exception e){
          return 0;
      }
    }

    @Override
    public LotteryRecord save(LotteryRecord lotteryRecord){
        LotteryRecord lotteryRecord1 = lotteryRecordDao.find("sn", lotteryRecord.getSn());
        if(lotteryRecord1==null){
            lotteryRecord1 = super.save(lotteryRecord);
            // 加入到下注缓存
            addCache(lotteryRecord1);
        }else{
            lotteryRecord1.setDrawCode(lotteryRecord.getDrawCode());
            lotteryRecord1.setDrawTime(lotteryRecord.getDrawTime());
            lotteryRecord1 = super.update(lotteryRecord1);
        }
        List<Map<String, Object>> maps = lotteryRecordNumService.create(lotteryRecord1);
        if(!maps.isEmpty()){
            lotteryRecord1.setOpenInfo(JsonUtils.toJson(maps));
            List<Integer> drawNums = lotteryRecord1.getDrawNums();
            if(!drawNums.isEmpty()){
                lotteryRecord1.setPredictInfo(updatePredictInfo(lotteryRecord1));
            }
        }
        if(lotteryRecord1.getOrder()==null){
            lotteryRecord1.setOrder(getMaxOrder(lotteryRecord1)+1);
        }
        // 更新BetRecord的信息
        betRecordService.load(lotteryRecord1);
        return super.update(lotteryRecord1);
    }

    @Override
    public void addCache(LotteryRecord lotteryRecord) {
        BetInfo betInfo = betInfoService.getCurrent();
        Integer num = betInfo.getNum();


        String s = redisService.get("sendInfo");
        Map<String,Object> sendInfo = new HashMap<>();
        sendInfo.put("sn",lotteryRecord.getSn()%100000);
        String type = getType(betInfo, lotteryRecord,sendInfo);
        sendInfo.put("num",num);
        sendInfo.put("stop",betInfo.getStop());
        Map<String,Object> map = new HashMap<>(sendInfo);
        try {
            sendInfo = JsonUtils.toObject(s, new TypeReference<>() {
            });
            sendInfo.putAll(map);
            long l = Long.parseLong(sendInfo.get("sn") + "");
            if(l<lotteryRecord.getSn()%100000){
                sendInfo.put("sn",lotteryRecord.getSn()%100000);
                if(StringUtils.isNotBlank(type)){
                    sendInfo.put("type",type);
                    sendInfo.put("send",betInfo.getOpen()==1?1:0);
                }else{
                    sendInfo.put("send",0);
                }
                sendInfo.put("num",num);
                sendInfo.put("send",betInfo.getOpen()==1?1:0);
                sendInfo.put("stop",betInfo.getStop());
                redisService.set("sendInfo",JsonUtils.toJson(sendInfo));
            }else{
                if(StringUtils.isNotBlank(type)){
                    sendInfo.put("type",type);
                    sendInfo.put("send",betInfo.getOpen()==1?1:0);
                }else{
                    sendInfo.put("send",0);
                }
            }
        }catch (Exception e){
            if(StringUtils.isNotBlank(type)){
                sendInfo.put("type",type);
                sendInfo.put("send",betInfo.getOpen()==1?1:0);
            }else{
                sendInfo.put("send",0);
            }
        }
        if(redisService.hasKey("stopBetting")){
            sendInfo.put("send","0");
        }
        System.out.println(lotteryRecord.getSn()+":"+JsonUtils.toJson(sendInfo));
        redisService.set("sendInfo",JsonUtils.toJson(sendInfo));
    }

    private String getType(BetInfo betInfo,LotteryRecord lotteryRecord,Map<String,Object> sendInfo) {
        redisService.delete("stopBetting");
        String type1 = betInfo.getType();
        LotteryRecord prev1 = getPrev(lotteryRecord);
        //判断这两把有没有投
        BetRecord betRecord1 = betRecordService.findBySn(prev1.getSn());
        if(betRecord1==null){
           // 说明最近一把没投,直接投100
            sendInfo.put("msg","上一局"+prev1.getSn()+"未投，本次投注"+betInfo.getMoney());
            sendInfo.put("money",betInfo.getMoney());
            lotteryRecord.setBetMoney(betInfo.getMoney()+0.0);
        }else{
            if(betRecord1.getWin()==null){
                return type1;
            }
            // 说明最近一把投了。那就判断输赢。如果赢了。继续100，否则5
            if(betRecord1.getWin()==1){
                sendInfo.put("msg","上一局"+prev1.getSn()+"投注赢了，本次继续投注"+betInfo.getMoney());
                sendInfo.put("money",betInfo.getMoney());
                lotteryRecord.setBetMoney(betInfo.getMoney()+0.0);
            }else{
                try {
                    Integer failCount = betRecordService.getFailCount(lotteryRecord);
                    Integer amount = jdbcTemplate.queryForObject("select amount from failbet where orders=? limit 1",Integer.class,failCount);
                    if(amount==null){
                        sendInfo.put("msg","上一局"+prev1.getSn()+"投注输了，本次连续输了"+failCount+"次，未配置倍投金额，本次投注"+(betInfo.getMoney()*2));
                        sendInfo.put("money",(betInfo.getMoney()*2));
                        lotteryRecord.setBetMoney((betInfo.getMoney()*2)+0.0);
                    }else{
                        sendInfo.put("msg","上一局"+prev1.getSn()+"投注输了，本次连续输了"+failCount+"次，本次投注"+amount);
                        sendInfo.put("money",amount);
                        lotteryRecord.setBetMoney(amount+0.0);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    sendInfo.put("msg","上一局"+prev1.getSn()+"投注输了,配置数据转换失败，本次投注"+betInfo.getMoney()*2);
                    sendInfo.put("money",betInfo.getMoney()*2);
                    lotteryRecord.setBetMoney(betInfo.getMoney()+0.0);
                }
            }
        }
        betInfo.setStop(1);








        return type1;
    }

    @Override
    public LotteryRecord predict(Long lotteryCode,Long sn) {
        BetInfo betInfo = betInfoService.getCurrent();
        Integer num = betInfo.getNum();
        betInfo.setSn(sn);
        betInfoService.update(betInfo);
        List<PredictInfo> predictInfos = new ArrayList<>();
        LotteryRecord lotteryRecord = findBySn(sn);
        Map<Integer, Integer> oddResult = predictOdd(lotteryRecord);
        Map<Integer, Integer> largeResult = predictLarge(lotteryRecord);
        Map<Integer, String> numResult = predictNum(lotteryRecord);
        int length = 5;
        for (int i = 0; i < length; i++) {
            PredictInfo predictInfo = new PredictInfo();
            predictInfo.setPosition(i);
            predictInfo.setOdd(oddResult.get(i));
            predictInfo.setLarge(largeResult.get(i));
            predictInfo.setPredictNums(numResult.get(i));
            predictInfo.setCurrent(num - 1 == i);
            predictInfos.add(predictInfo);
        }
        lotteryRecord.setPredictInfo(predictInfos);
        List<Integer> drawNums = lotteryRecord.getDrawNums();
        if(!drawNums.isEmpty()){
            predictInfos = updatePredictInfo(lotteryRecord);
        }
        lotteryRecord.setPredictInfo(predictInfos);
        lotteryRecord.setPredictNumIndex(betInfo.getNum());
        lotteryRecord.setPredictType(betInfo.getType());

        return lotteryRecord;
    }

    private List<PredictInfo> updatePredictInfo(LotteryRecord lotteryRecord) {
        List<PredictInfo> predictInfos = lotteryRecord.getPredictInfo();
        if(predictInfos.isEmpty()){
            return predictInfos;
        }
        List<Integer> drawNums = lotteryRecord.getDrawNums();
        for (int i = 0; i < drawNums.size(); i++) {
            PredictInfo predictInfo = predictInfos.get(i);
            if(predictInfo.getPredictOdd()!=null){
                break;
            }

            Integer num = drawNums.get(i);
            Integer amountLarge = PredictUtils.isLarge(num);
            Integer amountOdd = PredictUtils.isOdd(num);

            predictInfo.setPredictOdd(amountOdd);
            predictInfo.setPredictLarge(amountLarge);
            predictInfo.setPredictNum(predictInfo.getPredictNums().contains(num + "") ?1:0);
        }
        return predictInfos;
    }

    @Override
    public LotteryRecord findBySn(Long sn) {
        return lotteryRecordDao.find("sn", sn);
    }

    @Override
    public LotteryRecord findLatestRecord(Long lotteryCode) {
        try {
            Long l = jdbcTemplate.queryForObject("select id from lotteryrecord where lotteryCode=? order by sn desc limit 1", Long.class, lotteryCode);
            return super.find(l);
        }catch (Exception e){
            return null;
        }
    }

    @Override
    public void batchSave(List<LotteryRecord> history) {
        List<Object[]> objects = new ArrayList<>();
        List<Object[]> objects1 = new ArrayList<>();
        for (int i = 0; i < history.size(); i++) {
            LotteryRecord lotteryRecord = history.get(i);
            lotteryRecord.setOrder(i+1);
            String drawCode = lotteryRecord.getDrawCode();
            List<Map<String, Object>> openInfo = new ArrayList<>();
            if(StringUtils.isNotEmpty(drawCode)){
                String[] split = drawCode.split(",");
                for (int j = 0; j < split.length; j++) {
                    Object [] object1 = new Object[6];
                    LotteryRecordNum lotteryRecordNum = new LotteryRecordNum();
                    Map<String,Object> map = new HashMap<>();
                    lotteryRecordNum.setOrder(j+1);
                    lotteryRecordNum.setLotteryCode(lotteryRecord.getLotteryCode());
                    lotteryRecordNum.setSn(lotteryRecord.getSn());
                    lotteryRecordNum.setNum(Integer.valueOf(split[j]));
                    lotteryRecordNum.setLotteryRecordOrder(lotteryRecord.getOrder());
                    lotteryRecordNum.setDate(lotteryRecord.getDate());
                    object1[0] = lotteryRecordNum.getOrder();
                    object1[1] = lotteryRecordNum.getLotteryCode();
                    object1[2] = lotteryRecordNum.getNum();
                    object1[3] = lotteryRecordNum.getSn();
                    object1[4] = lotteryRecordNum.getLotteryRecordOrder();
                    object1[5] = lotteryRecordNum.getDate();
                    objects1.add(object1);
                    map.put("index",lotteryRecordNum.getOrder());
                    map.put("amount",(lotteryRecordNum.getNum()+0.0)/100);
                    openInfo.add(map);
                }
            }
            Object [] object = new Object[7];
            // orders
            object[0] = lotteryRecord.getOrder();
            // date
            object[1] = lotteryRecord.getDate();
            // drawCode
            object[2] = lotteryRecord.getDrawCode();
            //drawTime
            object[3] = lotteryRecord.getDrawTime();
            //lotteryCode
            object[4] = lotteryRecord.getLotteryCode();
            //openInfo
            object[5] = JsonUtils.toJson(openInfo);
            //sn
            object[6] = lotteryRecord.getSn();


            objects.add(object);
        }
        jdbcTemplate.batchUpdate("insert into lotteryrecord(createdDate, lastModifiedDate, version, orders, date, drawCode, drawTime, lotteryCode, openInfo, sn) values (NOW(),NOW(),0,?,?,?,?,?,?,?) on duplicate key update version=version+1,lastModifiedDate=NOW(),orders=VALUES(orders)",objects);
        jdbcTemplate.batchUpdate("insert into lotteryrecordnum(createdDate, lastModifiedDate, version, orders, lotteryCode, num, sn,lotteryRecordOrder,date) VALUES (NOW(),NOW(),0,?,?,?,?,?,?) on duplicate key update version=version+1,lastModifiedDate=NOW()",objects1);
    }

    /**
     * 预测数字
     */
    public Map<Integer,String> predictNum(LotteryRecord lotteryRecord) {
        Map<Integer,String> result = new HashMap<>();
        // 最近第1期
        LotteryRecord prev1 = getPrev(lotteryRecord);
        List<Integer> drawNums1 = prev1.getDrawNums();
        for (int i = 0; i < drawNums1.size(); i++) {
           result.put(i,"-1");
        }

        return result;
    }

    /**
     * 预测奇偶性
     */
    public Map<Integer,Integer> predictOdd(LotteryRecord lotteryRecord) {
        Map<Integer,Integer> result = new HashMap<>();
        // 最近第1期
        LotteryRecord prev1 = getPrev(lotteryRecord);
        List<Integer> drawNums1 = prev1.getDrawNums();
        for (int i = 0; i < drawNums1.size(); i++) {
           if(i==0){
               result.put(i,1);
           }else{
               result.put(i,PredictUtils.isOdd(drawNums1.get(i)));
           }
        }
        return result;
    }

    private LotteryRecord getPrev(LotteryRecord lotteryRecord) {
        Integer index = 1;
        LotteryRecord prev = findBySn(lotteryRecord.getSn() - index);
        while (prev == null  || prev.getDrawNums().isEmpty()){
            index = index +1;
            prev = findBySn(lotteryRecord.getSn()-index);
        }
        return prev;
    }

    /**
     * 预测大小
     */
    public Map<Integer,Integer> predictLarge(LotteryRecord lotteryRecord) {
        Map<Integer,Integer> result = new HashMap<>();
        // 最近第1期
        LotteryRecord prev1 = getPrev(lotteryRecord);
        List<Integer> drawNums1 = prev1.getDrawNums();
        for (int i = 0; i < drawNums1.size(); i++) {
            result.put(i,PredictUtils.isLarge(drawNums1.get(i)));
        }
        return result;
    }

    @Override
    public Page<LotteryRecord> findPage(Pageable pageable, String date, String code) {
        org.springframework.data.domain.Page<LotteryRecord> all = lotteryRecordRepository.findAll((Specification<LotteryRecord>) (root, criteriaQuery, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();
            if (StringUtils.isNotBlank(date)) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("date"), date));
            }
            if (StringUtils.isNotBlank(code)) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("lotteryCode"), code));
            }
            criteriaQuery.where(predicate);
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("order")));
            return predicate;
        }, org.springframework.data.domain.Pageable.ofSize(pageable.getPageSize()).withPage(pageable.getPageNumber() - 1));

        return new Page<>(all.getContent(),all.getTotalElements(),pageable);
    }
}
